<?php

declare(strict_types=1);

namespace App\Utils;


use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use InvalidArgumentException;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\ValidationData;

class Jwt
{
    /**
     * @param array $clams
     * @param string $configType
     * @return string
     */
    public static function token(array $clams, string $configType = 'jwt.default'):string
    {
        $config = config($configType);
        $signer = di(Sha256::class);
        $builder = di(Builder::class);

        $time = time();

        $builder
            ->setIssuer($config['iss'])
            ->setId($config['id'])
            ->setSubject($config['sub'])
            ->expiresAt($time + $config['ttl'] * 60);

        foreach ($clams as $key => $value) {
            $builder->withClaim($key, $value);
        }

        $key = new Key($config['secret']);

        $token = $builder->getToken($signer, $key);

        return (string)$token;
    }

    /**
     * @param string $jwt
     * @param string $configType
     * @return bool
     */
    public static function verify(string $jwt, string $configType = 'jwt.default'): Token
    {
        $config = config($configType);
        $data = new ValidationData();
        $data->setIssuer($config['iss']);
        $data->setId($config['id']);
        $data->setSubject($config['sub']);

        $parser = new Parser();
        $signer = di(Sha256::class);
        $secret = $config['secret'];

        try {
            $token = $parser->parse($jwt);
        }catch (InvalidArgumentException $e){
            throw new BusinessException(ErrorCode::JWT_VALIDATE_ERROR);
        }


        //验证签名数据有效
        if (!$token->validate($data)) {
            throw new BusinessException(ErrorCode::JWT_VALIDATE_ERROR);
        }

        //验证秘钥
        if (!$token->verify($signer, $secret)) {
            throw new BusinessException(ErrorCode::JWT_SECRET_ERROR);
        }

        return $token;
    }

    public static function test()
    {
        $token = static::token(['uid' => 111]);
        var_dump($token->getHeaders());
        var_dump($token->getClaim('exp'));
        $verify = static::verify((string)$token);
        var_dump($verify);
    }
}